package com.leyou.seckill.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.leyou.common.auth.entity.UserHolder;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.common.vo.PageResult;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.BrandDTO;
import com.leyou.item.dto.CategoryDTO;
import com.leyou.seckill.dto.OrderSecKillDTO;
import com.leyou.seckill.dto.SeckillPolicyDTO;
import com.leyou.seckill.entity.TbSeckillPolicy;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.RocketMQConstants.TAGS.SECKILL_ORDER_TAGS;
import static com.leyou.common.constants.RocketMQConstants.TOPIC.ORDER_TOPIC_NAME;

/**
 * 秒杀管理平台业务
 * @author
 */
@Slf4j
@Service
public class SecKillService {
    @Autowired
    private TbSeckillPolicyService tbSeckillPolicyService;
    @Autowired
    private ItemClient itemClient;

    @Autowired
    private SeckillRedisService seckillRedisService;

    /**
     * 分页查询 秒杀信息
     *
     * @param page
     * @param rows
     * @param key
     * @param state 1-未开始 2-进行中  3-已结束
     * @return
     */
    public PageResult<SeckillPolicyDTO> findSecKillByPage(Integer page, Integer rows, String key, Integer state) {

        IPage<TbSeckillPolicy> page1 = new Page<>(page, rows);
        QueryWrapper<TbSeckillPolicy> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.lambda().like(TbSeckillPolicy::getTitle, key);
        }
        if (state != null) {
            Date now = new Date();
            switch (state) {
                case 1:
                    queryWrapper.lambda().gt(TbSeckillPolicy::getBeginTime, now);
                    break;
                case 2:
                    queryWrapper.lambda().lt(TbSeckillPolicy::getBeginTime, now).gt(TbSeckillPolicy::getEndTime, now);
                    break;
                case 3:
                    queryWrapper.lambda().lt(TbSeckillPolicy::getEndTime, now);
                    break;

            }
        }
        queryWrapper.orderByAsc("begin_time");
        IPage<TbSeckillPolicy> policyIPage = tbSeckillPolicyService.page(page1, queryWrapper);
        if (policyIPage == null || CollectionUtils.isEmpty(policyIPage.getRecords())) {
            throw new LyException(ExceptionEnum.SECKILL_NOT_FOUND);
        }

        List<TbSeckillPolicy> tbSeckillPolicyList = policyIPage.getRecords();
        List<SeckillPolicyDTO> seckillPolicyDTOS = BeanHelper.copyWithCollection(tbSeckillPolicyList, SeckillPolicyDTO.class);
        this.handleCategoryAndBrandName(seckillPolicyDTOS);
        return new PageResult<SeckillPolicyDTO>( policyIPage.getTotal(), policyIPage.getPages(),seckillPolicyDTOS);
    }

    /**
     * 处理 品牌名称 和 分类名称
     *
     * @param seckillPolicyDTOS
     */
    private void handleCategoryAndBrandName(List<SeckillPolicyDTO> seckillPolicyDTOS) {

        for (SeckillPolicyDTO seckillPolicyDTO : seckillPolicyDTOS) {
            //通过brandId查询brandName
            Long brandId = seckillPolicyDTO.getBrandId();
            BrandDTO brandDTO = itemClient.findBrandById(brandId);
            seckillPolicyDTO.setBrandName(brandDTO.getName());
            //查询categoryName  结果如 ：手机/手机通讯/手机    1级分类名/2级分类名/3级分类名
            List<Long> cids = seckillPolicyDTO.getCategorys();
            List<CategoryDTO> categoryDTOList = itemClient.findCategoryListByIds(cids);
            String categoryNames = categoryDTOList.stream().map(CategoryDTO::getName).collect(Collectors.joining("/"));
            seckillPolicyDTO.setCategoryName(categoryNames);
        }
    }

    /**
     * 根据id 查询 秒杀信息
     *
     * @param id
     * @return
     */
    public SeckillPolicyDTO findSecKillById(Long id) {
        TbSeckillPolicy tbSeckillPolicy = tbSeckillPolicyService.getById(id);
        if (tbSeckillPolicy == null) {
            throw new LyException(ExceptionEnum.SECKILL_NOT_FOUND);
        }
        return BeanHelper.copyProperties(tbSeckillPolicy, SeckillPolicyDTO.class);
    }

    /**
     * 添加秒杀商品信息
     *
     * @param seckillPolicy
     */
    public void addSecKill(TbSeckillPolicy seckillPolicy) {
        //获取秒杀日期 yyyy-MM-dd
        String secKillDay = new DateTime(seckillPolicy.getBeginTime()).toString("yyyy-MM-dd");
//        设置秒杀库存
        seckillPolicy.setStockCount(seckillPolicy.getNum());
//        设置秒杀 结束时间，默认为 开始2个小时后结束
        Date endTime = new DateTime(seckillPolicy.getBeginTime()).plusHours(2).toDate();
        seckillPolicy.setEndTime(endTime);
//        设置秒杀 日期
        seckillPolicy.setSecKillDate(secKillDay);
        boolean b = tbSeckillPolicyService.save(seckillPolicy);
        if (!b) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        seckillRedisService.saveSeckillToRedis(seckillPolicy); //保存redis数据

    }

    /**
     * 修改秒杀信息
     *
     * @param seckillPolicy
     */
    public void updateSecKill(TbSeckillPolicy seckillPolicy) {
        //获取秒杀日期 yyyy-MM-dd
        String secKillDay = new DateTime(seckillPolicy.getBeginTime()).toString("yyyy-MM-dd");
        // 设置秒杀库存
        seckillPolicy.setStockCount(seckillPolicy.getNum());
//        设置秒杀 结束时间，默认为 开始2个小时后结束
        Date endTime = new DateTime(seckillPolicy.getBeginTime()).plusHours(2).toDate();
        seckillPolicy.setEndTime(endTime);
        //        设置秒杀 日期
        seckillPolicy.setSecKillDate(secKillDay);
        boolean b = tbSeckillPolicyService.updateById(seckillPolicy);
        if (!b) {
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        seckillRedisService.removeSeckillFromRedis(seckillPolicy.getId()); //先删除以前的redis数据
        seckillRedisService.saveSeckillToRedis(seckillPolicy); //保存redis数据

    }

    /**
     * 删除 秒杀信息
     *
     * @param id
     */
    public void deleteSecKill(Long id) {
//        先把要删除的数据查询出来
        TbSeckillPolicy tbSeckillPolicy = tbSeckillPolicyService.getById(id);
        boolean b = tbSeckillPolicyService.removeById(id);
        if (!b) {
            throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        }

        seckillRedisService.removeSeckillFromRedis(id); //先删除以前的redis数据
    }

    public List<SeckillPolicyDTO> findSeckillListByDate(String nowDate) {
        QueryWrapper<TbSeckillPolicy> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TbSeckillPolicy::getSecKillDate,nowDate);
        List<TbSeckillPolicy> tbSeckillPolicies = tbSeckillPolicyService.list(queryWrapper);

        if(CollectionUtils.isEmpty(tbSeckillPolicies)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(tbSeckillPolicies,SeckillPolicyDTO.class);


    }


    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public Long saveSeckillOrder(OrderSecKillDTO orderSecKillDTO) {

        long orderId = idWorker.nextId();



//            1、判断是否有登录人
        String userId = UserHolder.getUserId();
        if(StringUtils.isEmpty(userId)){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

        Long seckillId = orderSecKillDTO.getSeckillId();  //秒杀商品的id
//            2、判断时间  当前时间是否在此商品的秒杀时间范围之内
//                  每个秒杀商品都有  开始时间     当前时间    结束时间
//                从redis中查询当前秒杀商品
       Boolean  isJudgeTime =   seckillRedisService.judgeTime(seckillId);
       if(!isJudgeTime){
           throw new LyException(ExceptionEnum.SECKILL_END_ERROR);
       }
//            3、判断库存 使用redis队列的方式判断库存
        Boolean  hasStock =   seckillRedisService.judgeStockCount(seckillId);
        if(!hasStock){
            throw new LyException(ExceptionEnum.SECKILL_NOT_FOUND);
        }

//        4、向mq中发送一个保存秒杀订单的任务



        orderSecKillDTO.setOrderId(orderId);
        orderSecKillDTO.setUserId(Long.parseLong(userId));
        rocketMQTemplate.convertAndSend(ORDER_TOPIC_NAME+":"+SECKILL_ORDER_TAGS,orderSecKillDTO);
        return orderId;
    }

    public void stockMinus(Long seckillId) {
        tbSeckillPolicyService.stockMinus(seckillId);
    }
}
